#include "MSqlConnectionPool.h"

using namespace NsMSql;

QMutex MSqlConnectionPool::m_mutex;
QWaitCondition MSqlConnectionPool::m_waitConnection;
MSqlConnectionPool* MSqlConnectionPool::m_pInstance = NULL;

NsMSql::MSqlConnectionPool::MSqlConnectionPool()
{
    m_maxWaitTime = 1000;
    m_waitInterval = 200;
}

NsMSql::MSqlConnectionPool::~MSqlConnectionPool()
{
    // 销毁连接池的时候删除所有的连接
    QMapIterator<QString, MSqlConnection> iter(m_nameConnectionMap);
    while (iter.hasNext()) {
        iter.next();
        MSqlConnection sqlConnection = iter.value();
        sqlConnection.remove();
    }
}

MSqlConnectionPool& NsMSql::MSqlConnectionPool::getInstance()
{
    if (NULL == m_pInstance) {
        QMutexLocker locker(&m_mutex);
        if (NULL == m_pInstance) {
            m_pInstance = new MSqlConnectionPool();
        }
    }

    return *m_pInstance;
}

void NsMSql::MSqlConnectionPool::init(const MDatabaseAttr& databaseAttr)
{
    MSqlConnectionPool& pool = MSqlConnectionPool::getInstance();

    //第一次初始化
    if (pool.m_nameConnectionMap.size() == 0)
    {
        //开启多连接
        if (databaseAttr.enableMultipleConnect)
        {
            //初始化initialConnectNum数量的连接
            QString connectionName;
            for (int i = 0; i < databaseAttr.initialConnectNum; i++)
            {
                MSqlConnection sqlConnection(databaseAttr);
                connectionName = QString("Connection-%1").arg(i);
                if (sqlConnection.open(connectionName))    // 有效的连接放入 m_unusedConnectionNames
                {
                    pool.m_unusedConnectionNames.enqueue(connectionName);
                    pool.m_nameConnectionMap[connectionName] = sqlConnection;
                }
            }
        }
        else
        {
            //初始化默认连接
            MSqlConnection defaultSqlConnection(databaseAttr);
            if (defaultSqlConnection.open())
            {
                pool.m_defaultConnectionName = defaultSqlConnection.getConnectionName();
                pool.m_nameConnectionMap[pool.m_defaultConnectionName] = defaultSqlConnection;
            }
        }
    }
}

MSqlConnection NsMSql::MSqlConnectionPool::getConnection()
{
    MSqlConnectionPool& pool = MSqlConnectionPool::getInstance();
    MSqlConnection sqlConnection;
    QString connectionName;

    //多连接功能下才需要连接池调度
    if (pool.m_dbAttr.enableMultipleConnect)
    {
        //原子锁
        QMutexLocker locker(&m_mutex);
        // 已创建连接数
        int connectionCount = pool.m_unusedConnectionNames.size() + pool.m_usedConnectionNames.size();
        // 如果连接已经用完，等待 waitInterval 毫秒看看是否有可用连接，最长等待 maxWaitTime 毫秒
        for (int i = 0;
            i < pool.m_maxWaitTime && pool.m_unusedConnectionNames.size() == 0 && connectionCount == pool.m_dbAttr.maxConnectionNum;
            i += pool.m_waitInterval)
        {
            m_waitConnection.wait(&m_mutex, pool.m_waitInterval);
            // 重新计算已创建连接数
            connectionCount = pool.m_unusedConnectionNames.size() + pool.m_usedConnectionNames.size();
        }

        if (pool.m_unusedConnectionNames.size() > 0)
        {
            // 有已经回收的连接，复用它们
            connectionName = pool.m_unusedConnectionNames.dequeue();
            sqlConnection = pool.m_nameConnectionMap[connectionName];
        }
        else if (connectionCount < pool.m_dbAttr.maxConnectionNum)
        {
            // 没有已经回收的连接，但是没有达到最大连接数，则创建新的连接,序号从0开始计
            connectionName = QString("Connection-%1").arg(connectionCount);
            if (sqlConnection.open(pool.m_dbAttr, connectionName))    // 有效的连接才放入 m_usedConnectionNames
            {
                pool.m_usedConnectionNames.enqueue(connectionName);
                pool.m_nameConnectionMap[connectionName] = sqlConnection;
            }
        }
        else
        {
            // 已经达到最大连接数
            qDebug() << "Cannot create more connections.";
        }
    }
    else    //单连接状态下使用默认连接即可
    {
        if (pool.m_nameConnectionMap.contains(pool.m_defaultConnectionName))
            sqlConnection = pool.m_nameConnectionMap[pool.m_defaultConnectionName];
    }

	return sqlConnection;
}

void NsMSql::MSqlConnectionPool::releaseConnection(MSqlConnection sqlConnection)
{
    MSqlConnectionPool& pool = MSqlConnectionPool::getInstance();
    QString connectionName = sqlConnection.getConnectionName();

    // 如果是我们创建的连接，从 used 里删除，放入 unused 里
    if (pool.m_usedConnectionNames.contains(connectionName)) {
        QMutexLocker locker(&m_mutex);
        pool.m_usedConnectionNames.removeOne(connectionName);
        pool.m_unusedConnectionNames.enqueue(connectionName);
        m_waitConnection.wakeOne();
    }
}

void NsMSql::MSqlConnectionPool::close()
{
    QMutexLocker locker(&m_mutex);
    delete m_pInstance;
    m_pInstance = NULL;
}

